package com.shermanzhou.springbootflowable.demo.custom.service;

import cn.hutool.core.collection.CollectionUtil;
import com.shermanzhou.springbootflowable.demo.custom.mapper.CustomActQueryMapper;
import com.shermanzhou.springbootflowable.demo.custom.mapper.CustomActUpdateMapper;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.ManagementService;
import org.flowable.engine.common.impl.cmd.CustomSqlExecution;
import org.flowable.engine.impl.cmd.AbstractCustomSqlExecution;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhouchaoqun02
 * @date 2020-06-14 19:44
 */
public class ProcessInstanceCopyService {
    private final static String TABLE_ACT_HI_PROCINST = "act_hi_procinst";
    private final static String TABLE_ACT_RU_EXECUTION = "act_ru_execution";
    private final static String TABLE_ACT_HI_ACTINST = "act_hi_actinst";
    private final static String TABLE_ACT_HI_TASKINST = "act_hi_taskinst";
    private final static String TABLE_ACT_HI_VARINST = "act_hi_varinst";
//    private final static String TABLE_ACT_RU_ACTINST = "act_ru_actinst";
    private final static String TABLE_ACT_RU_TASK = "act_ru_task";
    private final static String TABLE_ACT_RU_VARIABLE = "act_ru_variable";
    private final static String TABLE_ACT_GE_BYTEARRAY = "act_ge_bytearray";

    private final static String COLUMN_PROC_DEF_ID_ = "PROC_DEF_ID_";
    private final static String COLUMN_BYTEARRAY_ID_ = "BYTEARRAY_ID_";

    private ManagementService normalManagementService;
    private ManagementService simulateManagementService;

    public ProcessInstanceCopyService(ManagementService normalManagementService, ManagementService simulateManagementService) {
        this.normalManagementService = normalManagementService;
        this.simulateManagementService = simulateManagementService;
    }

    public void copyProcessInstanceFromNormalToSimulate(String procInstId, String procDefId) {
        copyEntities(TABLE_ACT_HI_PROCINST, procInstId, procDefId);
        copyEntities(TABLE_ACT_RU_EXECUTION, procInstId, procDefId);
        copyEntities(TABLE_ACT_HI_ACTINST, procInstId, procDefId);
        copyEntities(TABLE_ACT_HI_TASKINST, procInstId, procDefId);
        copyEntities(TABLE_ACT_HI_VARINST, procInstId, procDefId);
//        copyEntities(TABLE_ACT_RU_ACTINST, procInstId, procDefId);
        copyEntities(TABLE_ACT_RU_TASK, procInstId, procDefId);

        copyVarEntities(procInstId, procDefId);
    }

    public void copyEntities(String table, String procInstId, String prcDefId) {
        List<Map<String, Object>> entities = selectFromNormal(table, procInstId);
        insertIntoSimulate(table, entities, prcDefId);
    }

    public void copyVarEntities(String procInstId, String prcDefId) {
        List<Map<String, Object>> entities = selectFromNormal(TABLE_ACT_RU_VARIABLE, procInstId);
        List<String> ids = entities.stream().map(e -> (String) e.get(COLUMN_BYTEARRAY_ID_)).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(ids)) {
            List<Map<String, Object>> byteArrayList = selectGeByteArray(ids);
            insertIntoSimulate(TABLE_ACT_GE_BYTEARRAY, byteArrayList, prcDefId);
        }
        insertIntoSimulate(TABLE_ACT_RU_VARIABLE, entities, prcDefId);
    }

    public List<Map<String, Object>> selectFromNormal(String table, String procInstId) {
        CustomSqlExecution<CustomActQueryMapper, List<Map<String, Object>>> customSqlExecution = new AbstractCustomSqlExecution<CustomActQueryMapper, List<Map<String, Object>>>(CustomActQueryMapper.class) {
            @Override
            public List<Map<String, Object>> execute(CustomActQueryMapper customMapper) {
                return customMapper.select(table, procInstId);
            }
        };
        return normalManagementService.executeCustomSql(customSqlExecution);
    }

    public List<Map<String, Object>> selectGeByteArray(List<String> ids) {
        CustomSqlExecution<CustomActQueryMapper, List<Map<String, Object>>> customSqlExecution = new AbstractCustomSqlExecution<CustomActQueryMapper, List<Map<String, Object>>>(CustomActQueryMapper.class) {
            @Override
            public List<Map<String, Object>> execute(CustomActQueryMapper customMapper) {
                return customMapper.selectGeByteArray(ids);
            }
        };
        return normalManagementService.executeCustomSql(customSqlExecution);
    }

    public Integer insertIntoSimulate(String table, List<Map<String, Object>> entites, String prcDefId) {
        CustomSqlExecution<CustomActUpdateMapper, Integer> customSqlExecution = new AbstractCustomSqlExecution<CustomActUpdateMapper, Integer>(CustomActUpdateMapper.class) {
            @Override
            public Integer execute(CustomActUpdateMapper customMapper) {
                entites.forEach(e -> {
                    if (e.containsKey(COLUMN_PROC_DEF_ID_)) {
                        e.put(COLUMN_PROC_DEF_ID_, prcDefId);
                    }
                });
                return entites.stream().mapToInt(entity -> customMapper.insert(table, entity)).sum();
            }
        };
        return simulateManagementService.executeCustomSql(customSqlExecution);
    }
}